<template>
  <van-dialog
    v-model:show="visible"
    :title="title"
    :width="width"
    :message="message"
    :message-align="messageAlign"
    :theme="theme"
    :show-cancel-button="showCancelButton"
    :show-confirm-button="showConfirmButton"
    :cancel-button-text="cancelButtonText"
    :confirm-button-text="confirmButtonText"
    :cancel-button-color="cancelButtonColor"
    :confirm-button-color="confirmButtonColor"
    :overlay="overlay"
    :overlay-class="overlayClass"
    :overlay-style="overlayStyle"
    :close-on-click-overlay="closeOnClickOverlay"
    :close-on-popstate="closeOnPopstate"
    :lazy-render="lazyRender"
    :lock-scroll="lockScroll"
    :allow-html="allowHtml"
    :before-close="beforeClose"
    :transition="transition"
    :get-container="getContainer"
    @confirm="handleConfirm"
    @cancel="handleCancel"
    @open="handleOpen"
    @close="handleClose"
    @opened="handleOpened"
    @closed="handleClosed"
  >
    <!-- 自定义标题 -->
    <template v-if="$slots.title" #title>
      <slot name="title" />
    </template>

    <!-- 自定义内容 -->
    <template v-if="$slots.default" #default>
      <div class="base-dialog__content">
        <slot />
      </div>
    </template>

    <!-- 自定义底部 -->
    <template v-if="$slots.footer" #footer>
      <slot name="footer" />
    </template>
  </van-dialog>
</template>

<script>
import { ref, computed, watch, defineComponent } from 'vue'

export default defineComponent({
  name: 'BaseDialog',
  props: {
    /**
     * 是否显示对话框
     */
    modelValue: {
      type: Boolean,
      default: false
    },
    /**
     * 标题
     */
    title: {
      type: String,
      default: ''
    },
    /**
     * 对话框宽度
     */
    width: {
      type: [Number, String],
      default: 320
    },
    /**
     * 文本内容
     */
    message: {
      type: [String, Function],
      default: ''
    },
    /**
     * 内容对齐方式
     */
    messageAlign: {
      type: String,
      default: 'center',
      validator: (value) => ['left', 'center', 'right'].includes(value)
    },
    /**
     * 样式风格
     */
    theme: {
      type: String,
      default: 'default',
      validator: (value) => ['default', 'round-button'].includes(value)
    },
    /**
     * 是否显示取消按钮
     */
    showCancelButton: {
      type: Boolean,
      default: false
    },
    /**
     * 是否显示确认按钮
     */
    showConfirmButton: {
      type: Boolean,
      default: true
    },
    /**
     * 取消按钮文字
     */
    cancelButtonText: {
      type: String,
      default: '取消'
    },
    /**
     * 确认按钮文字
     */
    confirmButtonText: {
      type: String,
      default: '确认'
    },
    /**
     * 取消按钮颜色
     */
    cancelButtonColor: {
      type: String,
      default: ''
    },
    /**
     * 确认按钮颜色
     */
    confirmButtonColor: {
      type: String,
      default: ''
    },
    /**
     * 是否显示遮罩层
     */
    overlay: {
      type: Boolean,
      default: true
    },
    /**
     * 自定义遮罩层类名
     */
    overlayClass: {
      type: String,
      default: ''
    },
    /**
     * 自定义遮罩层样式
     */
    overlayStyle: {
      type: Object,
      default: () => ({})
    },
    /**
     * 是否在点击遮罩层后关闭
     */
    closeOnClickOverlay: {
      type: Boolean,
      default: false
    },
    /**
     * 是否在页面回退时自动关闭
     */
    closeOnPopstate: {
      type: Boolean,
      default: true
    },
    /**
     * 是否开启延迟渲染
     */
    lazyRender: {
      type: Boolean,
      default: true
    },
    /**
     * 是否锁定背景滚动
     */
    lockScroll: {
      type: Boolean,
      default: true
    },
    /**
     * 是否允许 message 内容中渲染 HTML
     */
    allowHtml: {
      type: Boolean,
      default: false
    },
    /**
     * 关闭前的回调函数
     */
    beforeClose: {
      type: Function,
      default: null
    },
    /**
     * 动画类名
     */
    transition: {
      type: String,
      default: ''
    },
    /**
     * 指定挂载的节点
     */
    getContainer: {
      type: [String, Function],
      default: 'body'
    },
    /**
     * 对话框类型
     */
    type: {
      type: String,
      default: 'default',
      validator: (value) => ['default', 'alert', 'confirm', 'prompt'].includes(value)
    },
    /**
     * 输入框占位符（prompt 类型）
     */
    inputPlaceholder: {
      type: String,
      default: '请输入'
    },
    /**
     * 输入框初始值（prompt 类型）
     */
    inputValue: {
      type: String,
      default: ''
    },
    /**
     * 输入框类型（prompt 类型）
     */
    inputType: {
      type: String,
      default: 'text'
    },
    /**
     * 输入框验证器（prompt 类型）
     */
    inputValidator: {
      type: Function,
      default: null
    },
    /**
     * 输入框验证错误信息（prompt 类型）
     */
    inputErrorMessage: {
      type: String,
      default: '输入的数据不合法!'
    }
  },
  emits: ['update:modelValue', 'confirm', 'cancel', 'open', 'close', 'opened', 'closed'],
  setup(props, { emit }) {
    const promptValue = ref(props.inputValue)
    const promptError = ref('')

    /**
     * 对话框显示状态
     */
    const visible = computed({
      get: () => props.modelValue,
      set: (value) => emit('update:modelValue', value)
    })

    /**
     * 确认事件处理
     */
    const handleConfirm = () => {
      if (props.type === 'prompt') {
        // 验证输入
        if (props.inputValidator) {
          const result = props.inputValidator(promptValue.value)
          if (result !== true) {
            promptError.value = result || props.inputErrorMessage
            return
          }
        }
        emit('confirm', promptValue.value)
      } else {
        emit('confirm')
      }
    }

    /**
     * 取消事件处理
     */
    const handleCancel = () => {
      emit('cancel')
    }

    /**
     * 打开事件处理
     */
    const handleOpen = () => {
      if (props.type === 'prompt') {
        promptValue.value = props.inputValue
        promptError.value = ''
      }
      emit('open')
    }

    /**
     * 关闭事件处理
     */
    const handleClose = () => {
      emit('close')
    }

    /**
     * 打开完成事件处理
     */
    const handleOpened = () => {
      emit('opened')
    }

    /**
     * 关闭完成事件处理
     */
    const handleClosed = () => {
      emit('closed')
    }

    // 监听输入值变化
    watch(() => props.inputValue, (newValue) => {
      promptValue.value = newValue
    })

    return {
      visible,
      promptValue,
      promptError,
      handleConfirm,
      handleCancel,
      handleOpen,
      handleClose,
      handleOpened,
      handleClosed
    }
  }
})
</script>

<style lang="scss" scoped>
.base-dialog {
  &__content {
    padding: 16px 24px;
    font-size: 14px;
    line-height: 1.6;
    color: #323233;
  }

  &__prompt {
    margin-top: 16px;
  }

  &__prompt-input {
    width: 100%;
    padding: 8px 12px;
    font-size: 14px;
    border: 1px solid #ebedf0;
    border-radius: 4px;
    outline: none;

    &:focus {
      border-color: #1989fa;
    }

    &.error {
      border-color: #ee0a24;
    }
  }

  &__prompt-error {
    margin-top: 8px;
    font-size: 12px;
    color: #ee0a24;
  }
}

// 全局样式覆盖
:global(.van-dialog) {
  border-radius: 8px;
  overflow: hidden;

  .van-dialog__header {
    padding: 20px 24px 16px;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    text-align: center;
  }

  .van-dialog__content {
    padding: 0 24px 20px;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
    color: #646566;
  }

  .van-dialog__footer {
    display: flex;
    overflow: hidden;
    user-select: none;
  }

  .van-dialog__cancel,
  .van-dialog__confirm {
    flex: 1;
    height: 48px;
    margin: 0;
    border: 0;
    border-radius: 0;
  }

  .van-dialog__cancel {
    color: #646566;
    background-color: #fff;
    border-right: 1px solid #ebedf0;

    &:active {
      background-color: #f2f3f5;
    }
  }

  .van-dialog__confirm {
    color: #1989fa;
    background-color: #fff;

    &:active {
      background-color: #f2f3f5;
    }
  }

  &.van-dialog--round-button {
    .van-dialog__footer {
      position: relative;
      height: auto;
      padding: 8px 24px 24px;
      background-color: #fff;
    }

    .van-dialog__cancel,
    .van-dialog__confirm {
      height: 36px;
      border-radius: 18px;
    }

    .van-dialog__cancel {
      margin-right: 8px;
      color: #646566;
      background-color: #f7f8fa;
      border-right: none;
    }

    .van-dialog__confirm {
      margin-left: 8px;
      color: #fff;
      background-color: #1989fa;
    }
  }
}
</style>